/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package taskmanager2ndedition.server;

import taskmanager2ndedition.exceptions.ObjectNotFoundException;
import taskmanager2ndedition.exceptions.TaskNotFoundException;
import taskmanager2ndedition.exceptions.InvalidDateException;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import taskmanager2ndedition.ServerTaskInfo;
import taskmanager2ndedition.StatisticInfo;
import taskmanager2ndedition.Task;
import taskmanager2ndedition.TaskInfo;
import taskmanager2ndedition.exceptions.OldVersionException;

/**
 *
 * @author denaas
 */
public class TaskManager {
    private int userId;
    private static Storage<Task> storage;
    private static int currentTaskId = 0;
    
    public static void Init(Storage<Task> storage){
        TaskManager.storage = storage;
        
        int maxId = 0;
        List<Task> list = getAll();
        for(Task task: list){
            maxId = maxId < task.getId() ? task.getId() : maxId;
        }
        currentTaskId = maxId + 1;
    }
    
    public static List<Task> getAll(){
        return storage.getAll();
    }
    
    //wrong!!!!
    public static List<Task> getAllModified(){
        List<Task> modifiedTasks = new LinkedList<Task>();
        for (Task task: storage.getAll()){
            if (task.isModified()){
                modifiedTasks.add(task);
                task.setModified(false);
                storage.update(task);
            }
        }
        return modifiedTasks;
    }
    
    public TaskManager(int userId){
        this.userId = userId;    
    }

    public StatisticInfo calculateGroupStatistics(){
        StatisticInfo info = new StatisticInfo();
        for(TaskInfo task: storage.getGroup(userId)){
            if (task.getState() == Task.TaskState.Removed)
                continue;
            switch(task.getStatus()){
                case Closed:
                    info.nClosed++;
                    break;
                case Opened:
                    info.nOpened++;
                    break;
            }
        }
        return info;
    }
    
    public static StatisticInfo calculateAllStatistics(){
        StatisticInfo info = new StatisticInfo();
        for(TaskInfo task: storage.getAll()){
            if (task.getState() == Task.TaskState.Removed)
                continue;
            switch(task.getStatus()){
                case Closed:
                    info.nClosed++;
                    break;
                case Opened:
                    info.nOpened++;
                    break;
            }
        }
        return info;
    }
    
    public Task addTask(TaskInfo newTask) throws InvalidDateException{
        if(!validateDate(newTask.getExpirationDate())){
            throw new InvalidDateException();
        }
        Task task = new Task(newTask.getName(), newTask.getDescription(), newTask.getContacts(), newTask.getExpirationDate(), TaskInfo.TaskStatus.Opened, currentTaskId, userId);
        task.setState(TaskInfo.TaskState.Added);
        task.setModified(true);
        storage.add(task);
        currentTaskId++;
        return task;
    }
    
    public void editTask(ServerTaskInfo newTask) throws TaskNotFoundException, InvalidDateException, OldVersionException{
       if (userId != newTask.getUserId())
           return;
        
       Task task = findById(newTask.getId());
       if(isOldVersion(task, newTask)){
           throw new OldVersionException();
       }
       
       boolean modified = false;
       if (newTask.getName() != null && !task.getName().equals(newTask.getName())){
           task.setName(newTask.getName());
           modified = true;
       }
       if (newTask.getDescription() != null && !task.getDescription().equals(newTask.getDescription())){
           task.setDescription(newTask.getDescription());
           modified = true;
       }
       if (newTask.getContacts() != null && !task.getContacts().equals(newTask.getContacts())){
           task.setContacts(newTask.getContacts());
           modified = true;
       }
       if (newTask.getExpirationDate() != null && task.getExpirationDate().compareTo(newTask.getExpirationDate()) != 0){
           if (!validateDate(newTask.getExpirationDate())){
               throw new InvalidDateException();
           }
           task.setExpirationDate(newTask.getExpirationDate());
           modified = true;
       }
       if (newTask.getStatus() != null && task.getStatus() != newTask.getStatus()){
           task.setStatus(newTask.getStatus());
           modified = true;
       }
       if (modified){
           task.setState(TaskInfo.TaskState.Editted);
           task.setModified(true);
           task.incVersion();
           storage.update(task);
       }
       
    }
    
    public Task findById(int taskId) throws TaskNotFoundException{
        try{
            Task task = storage.get(taskId);
            if (task.getState() == Task.TaskState.Removed){
                throw new ObjectNotFoundException();
            }
            return task;
        }
        catch(ObjectNotFoundException e){
            throw new TaskNotFoundException();
        }
    }
    
    public List<Task> getGroup(){
        return storage.getGroup(userId);
    }
    
    public List<Task> getGroupModified(){
        List<Task> modifiedTasks = new LinkedList<Task>();
        for (Task task: storage.getGroup(userId)){
            if (task.isModified()){
                modifiedTasks.add(task);
                task.setModified(false);
                storage.update(task);
            }
        }
        return modifiedTasks;
    }
    
    public void removeTask(int id) throws TaskNotFoundException{
        try{
            Task task = findById(id);
            task.setState(TaskInfo.TaskState.Removed);
            task.setModified(true);
            storage.update(task);
            //storage.remove(id);
        }
        catch(ObjectNotFoundException e){
            throw new TaskNotFoundException();
        }               
    }
    
    public boolean validateDate(Date date){
        Date now = new Date();
        return now.before(date);
    }
    
    private boolean isOldVersion(ServerTaskInfo serverTask, ServerTaskInfo task){
       return serverTask.getVersion() > task.getVersion();
    }
}
